// JavaScript数组扁平化方法大全

console.log("=== JavaScript数组扁平化方法大全 ===\n");

// 测试数据
const simpleNested = [1, [2, 3], [4, [5, 6]]];
const deepNested = [1, [2, [3, [4, [5]]]]];
const complexNested = [1, [2, 3], [4, [5, 6]], [[7, 8], 9], [10, [11, [12, 13]]]];
const mixedTypes = [1, ['a', 'b'], [true, [null, undefined]], [NaN, [[], {}]]];

console.log("简单嵌套数组:", simpleNested);
console.log("深度嵌套数组:", deepNested);
console.log("复杂嵌套数组:", complexNested);
console.log("混合类型数组:", mixedTypes);
console.log("\n" + "=".repeat(60) + "\n");

// ===== 方法1: ES6 flat() 方法 =====
console.log("=== 方法1: ES6 flat() 方法 ===");
function flattenByFlat(arr, depth = 1) {
    return arr.flat(depth);
}

console.log("一层扁平化:", flattenByFlat(simpleNested));
console.log("两层扁平化:", flattenByFlat(simpleNested, 2));
console.log("完全扁平化:", flattenByFlat(complexNested, Infinity));
console.log("注意: 是ES2019(ES10)新增方法，兼容性需要考虑");

// ===== 方法2: 递归方法 =====
console.log("\n=== 方法2: 递归方法 ===");
function flattenRecursive(arr) {
    const result = [];
    arr.forEach(item => {
        if (Array.isArray(item)) {
            result.push(...flattenRecursive(item));
        } else {
            result.push(item);
        }
    });
    return result;
}

console.log("递归扁平化:", flattenRecursive(complexNested));

// ===== 方法3: reduce + 递归 =====
console.log("\n=== 方法3: reduce + 递归 ===");
function flattenByReduce(arr) {
    return arr.reduce((acc, curr) => {
        return acc.concat(Array.isArray(curr) ? flattenByReduce(curr) : curr);
    }, []);
}

console.log("reduce递归:", flattenByReduce(complexNested));

// ===== 方法4: 栈方法（迭代） =====
console.log("\n=== 方法4: 栈方法（迭代） ===");
function flattenByStack(arr) {
    const stack = [...arr];
    const result = [];
    
    while (stack.length > 0) {
        const next = stack.pop();
        if (Array.isArray(next)) {
            stack.push(...next);
        } else {
            result.push(next);
        }
    }
    
    return result.reverse();
}

console.log("栈方法:", flattenByStack(complexNested));

// ===== 方法5: while循环 + some() + concat() =====
console.log("\n=== 方法5: while循环 + some() + concat() ===");
function flattenByWhile(arr) {
    let flattened = [...arr];
    while (flattened.some(Array.isArray)) {
        flattened = [].concat(...flattened);
    }
    return flattened;
}

console.log("while循环:", flattenByWhile(complexNested));

// ===== 方法6: toString() + split() + map() =====
console.log("\n=== 方法6: toString() + split() + map() ===");
function flattenByToString(arr) {
    return arr.toString().split(',').map(item => {
        // 尝试转换为数字，如果不是数字则保持原字符串
        const num = Number(item);
        return isNaN(num) ? item : num;
    });
}

console.log("toString方法:", flattenByToString(simpleNested));
console.log("注意: 只适用于数字和字符串，会丢失其他类型");

// ===== 方法7: JSON方法 =====
console.log("\n=== 方法7: JSON方法 ===");
function flattenByJSON(arr) {
    const str = JSON.stringify(arr).replace(/\[|\]/g, '');
    return str ? str.split(',').map(item => {
        try {
            return JSON.parse(item);
        } catch {
            return item.replace(/"/g, '');
        }
    }) : [];
}

console.log("JSON方法:", flattenByJSON(simpleNested));
console.log("注意: 对特殊值处理有限制");

// ===== 方法8: 生成器函数 =====
console.log("\n=== 方法8: 生成器函数 ===");
function* flattenGenerator(arr) {
    for (const item of arr) {
        if (Array.isArray(item)) {
            yield* flattenGenerator(item);
        } else {
            yield item;
        }
    }
}

function flattenByGenerator(arr) {
    return [...flattenGenerator(arr)];
}

console.log("生成器方法:", flattenByGenerator(complexNested));

// ===== 方法9: 展开运算符 + concat() =====
console.log("\n=== 方法9: 展开运算符 + concat() ===");
function flattenBySpread(arr) {
    const flattened = [].concat(...arr);
    return flattened.some(Array.isArray) ? flattenBySpread(flattened) : flattened;
}

console.log("展开运算符:", flattenBySpread(complexNested));

// ===== 方法10: 指定深度的扁平化 =====
console.log("\n=== 方法10: 指定深度的扁平化 ===");
function flattenDepth(arr, depth = 1) {
    if (depth <= 0) return arr;
    
    return arr.reduce((acc, curr) => {
        if (Array.isArray(curr)) {
            acc.push(...flattenDepth(curr, depth - 1));
        } else {
            acc.push(curr);
        }
        return acc;
    }, []);
}

console.log("深度1:", flattenDepth(complexNested, 1));
console.log("深度2:", flattenDepth(complexNested, 2));
console.log("深度3:", flattenDepth(complexNested, 3));

// ===== 方法11: 尾递归优化版本 =====
console.log("\n=== 方法11: 尾递归优化版本 ===");
function flattenTailRecursive(arr, result = []) {
    for (let i = 0; i < arr.length; i++) {
        if (Array.isArray(arr[i])) {
            flattenTailRecursive(arr[i], result);
        } else {
            result.push(arr[i]);
        }
    }
    return result;
}

console.log("尾递归优化:", flattenTailRecursive(complexNested));

// ===== 方法12: 使用队列（广度优先） =====
console.log("\n=== 方法12: 使用队列（广度优先） ===");
function flattenByQueue(arr) {
    const queue = [...arr];
    const result = [];
    
    while (queue.length > 0) {
        const item = queue.shift();
        if (Array.isArray(item)) {
            queue.unshift(...item);
        } else {
            result.push(item);
        }
    }
    
    return result;
}

console.log("队列方法:", flattenByQueue(complexNested));

// ===== 方法13: 正则表达式方法 =====
console.log("\n=== 方法13: 正则表达式方法 ===");
function flattenByRegex(arr) {
    let str = JSON.stringify(arr);
    str = str.replace(/(\[|\])/g, '');
    return str ? str.split(',').map(item => {
        if (item === 'null') return null;
        if (item === 'undefined') return undefined;
        if (item === 'true') return true;
        if (item === 'false') return false;
        if (!isNaN(item) && item !== '') return Number(item);
        return item.replace(/"/g, '');
    }) : [];
}

console.log("正则表达式:", flattenByRegex(simpleNested));

// ===== 方法14: 函数式编程风格 =====
console.log("\n=== 方法14: 函数式编程风格 ===");
const flattenFunctional = arr => 
    arr.reduce((acc, val) => 
        acc.concat(Array.isArray(val) ? flattenFunctional(val) : val), []);

console.log("函数式风格:", flattenFunctional(complexNested));

// ===== 方法15: 类方法封装 =====
console.log("\n=== 方法15: 类方法封装 ===");
class ArrayFlattener {
    static flatten(arr, depth = Infinity) {
        if (depth <= 0) return arr;
        
        return arr.reduce((acc, curr) => {
            if (Array.isArray(curr)) {
                acc.push(...this.flatten(curr, depth - 1));
            } else {
                acc.push(curr);
            }
            return acc;
        }, []);
    }
    
    static flattenIterative(arr) {
        const result = [];
        const stack = arr.slice();
        
        while (stack.length) {
            const next = stack.pop();
            if (Array.isArray(next)) {
                stack.push(...next);
            } else {
                result.push(next);
            }
        }
        
        return result.reverse();
    }
}

console.log("类方法:", ArrayFlattener.flatten(complexNested));

// ===== 性能测试 =====
console.log("\n=== 性能测试 ===");

// 创建大型嵌套数组进行性能测试
function createLargeNestedArray(size, depth) {
    let arr = Array.from({length: size}, (_, i) => i);
    for (let i = 0; i < depth; i++) {
        arr = arr.map((item, index) => 
            index % 2 === 0 ? [item] : item
        );
    }
    return arr;
}

const largeArray = createLargeNestedArray(1000, 3);
console.log("测试数组长度:", largeArray.length);

function performanceTest(func, name, arr) {
    const start = performance.now();
    const result = func(arr);
    const end = performance.now();
    console.log(`${name}: ${(end - start).toFixed(2)}ms, 结果长度: ${result.length}`);
}

// 只测试主要方法，避免输出过长
console.log("\n主要方法性能对比:");
performanceTest(arr => arr.flat(Infinity), "flat(Infinity)", largeArray);
performanceTest(flattenRecursive, "递归方法", largeArray);
performanceTest(flattenByReduce, "reduce方法", largeArray);
performanceTest(flattenByStack, "栈方法", largeArray);
performanceTest(flattenByWhile, "while循环", largeArray);

// ===== 特殊情况处理 =====
console.log("\n=== 特殊情况处理 ===");

// 空数组处理
console.log("空数组:", flattenRecursive([]));
console.log("包含空数组:", flattenRecursive([1, [], [2, []], 3]));

// 稀疏数组处理
const sparseArray = [1, , , [2, , 3]];
console.log("稀疏数组:", sparseArray);
console.log("flat处理稀疏数组:", sparseArray.flat());
console.log("递归处理稀疏数组:", flattenRecursive(sparseArray));

// 循环引用检测
console.log("\n循环引用检测:");
function flattenWithCircularCheck(arr, visited = new WeakSet()) {
    const result = [];
    
    for (const item of arr) {
        if (Array.isArray(item)) {
            if (visited.has(item)) {
                console.log("检测到循环引用，跳过该数组");
                continue;
            }
            visited.add(item);
            result.push(...flattenWithCircularCheck(item, visited));
            visited.delete(item);
        } else {
            result.push(item);
        }
    }
    
    return result;
}

const circularArray = [1, [2, 3]];
circularArray.push(circularArray); // 创建循环引用
console.log("带循环引用检测的扁平化:", flattenWithCircularCheck([1, [2, [3, 4]]]));

console.log("\n=== 总结 ===");
console.log(`
数组扁平化方法选择建议：

📋 方法分类：
1. 原生方法: flat() - 最简单，ES2019+
2. 递归方法: 递归、reduce+递归 - 易理解，适合深嵌套
3. 迭代方法: 栈、队列、while循环 - 避免栈溢出
4. 转换方法: toString、JSON - 有类型限制
5. 高级方法: 生成器、类封装 - 灵活性高

🎯 使用建议：
- 简单场景: arr.flat() 或 arr.flat(Infinity)
- 兼容性要求: 递归方法或reduce方法  
- 深度嵌套/大数组: 栈方法或while循环
- 特定深度: flattenDepth函数
- 性能要求高: 原生flat() > 迭代方法 > 递归方法

⚠️ 注意事项：
- flat()方法IE不支持，需要polyfill
- 递归方法可能导致栈溢出
- toString/JSON方法会丢失数据类型
- 需要考虑稀疏数组和循环引用的处理
- 性能：原生方法 > 迭代方法 > 递归方法
`);

// ===== 实用工具函数 =====
console.log("\n=== 实用工具函数 ===");

// 获取数组嵌套深度
function getArrayDepth(arr) {
    if (!Array.isArray(arr)) return 0;
    return 1 + Math.max(0, ...arr.map(getArrayDepth));
}

console.log("简单嵌套深度:", getArrayDepth(simpleNested));
console.log("复杂嵌套深度:", getArrayDepth(complexNested));

// 安全的扁平化（避免栈溢出）
function safeFlatten(arr, maxDepth = 100) {
    if (getArrayDepth(arr) > maxDepth) {
        console.warn("数组嵌套过深，使用迭代方法");
        return flattenByStack(arr);
    }
    return flattenRecursive(arr);
}

console.log("安全扁平化:", safeFlatten(complexNested)); 